package com.zhuqi.config;

import com.zhuqi.filter.CodeFilter;
import com.zhuqi.service.impl.SysUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;


/**
 * @author zhuqi
 * @version 1.0
 * @date 2021/3/25 19:23
 * 安全配置类 配置登录走我们自己的方法 和 放行规则
 */
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserDetailsServiceImpl detailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private CodeFilter codeFilter;
    /**
     * 在认证的方法中配置我们自己的 UserDetailsService 类
     * 让登录走我们自己的方法
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(detailsService);
    }

    /**
     * 配置 HTTP 拦截规则和放行规则
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       // 配置页面登录的请求方法1:登录的页面 2: 登录调用的Url 3,4: 登录时可以设置获取前端用户登录设置的别名 5: 登录成功跳转的页面
        http.csrf().disable();
        // 将自定义的 过滤器 设置到认证过滤器之前执行
        http.addFilterBefore(codeFilter, UsernamePasswordAuthenticationFilter.class);
        http.formLogin()
                .loginPage("/toLogin")
                .loginProcessingUrl("/doLogin")
                .successForwardUrl("/index")
                .usernameParameter("username")
                .passwordParameter("password")
                .permitAll();
        // 配置登出URL
        http.logout()
                .logoutSuccessUrl("/toLogin")
                .permitAll();
        // 记住我 1:前端参数名 2:令牌存储的方式 3:用户的详细信息
        http.rememberMe().rememberMeParameter("remember-me")
                .tokenRepository(persistentTokenRepository())
                .userDetailsService(detailsService);
        // 放行验证码和跳转报错请求的路径
        http.authorizeRequests().antMatchers("/code","/codeError").permitAll();
        // 禁用跨站共计
        // 配置所有的请求都需要登录
        http.authorizeRequests().anyRequest().authenticated();
    }


    /**
     * 令牌存储库的配置
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    /**
     * 资源服务匹配放行
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers("/resources/**");
    }

    /**
     * 配置密码认证器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder instance = NoOpPasswordEncoder.getInstance();
        return instance ;
    }

    public static void main(String[] args) {
        String encode = new BCryptPasswordEncoder().encode("123456");
        System.out.println(encode);
    }
}
